package com.lgcns.andteam2.todaymenu;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileOutputStream;
import java.io.InputStream;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;

import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.NotificationManager;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.DialogInterface.OnCancelListener;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.text.TextUtils;
import android.util.Log;

/**
 * 서버의 DB 파일 버전을 체크하고, 버전이 다를 경우 새로 다운로드 한다.
 * 작업이 끝나면 MainActivity를 호출한다.
 */
public class IntroActivity extends Activity {
    private static final String TAG = IntroActivity.class.getSimpleName(); 
    private String mLocalDbVersion;
    private String mServerDbVersion;
    private String mServerDbZipFilename;
    private int mServerDbZipFileSize;
    private int mCurrentDownloadSize;
    private boolean mRemoveNotification = false;
    private ProgressDialog mDownloadProgressDialog;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        // Notification을 통해 진입하는 경우에는 Notification을 취소해 주어야 한다.
        Intent intent = getIntent();
        mRemoveNotification = intent.getBooleanExtra(Constants.EXTRA_REMOVE_NOTIFICATION, false);
        
        if(mRemoveNotification) {
            Log.d(TAG, "call from Notification");
            NotificationManager nm = (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);
            nm.cancel(Constants.NOTI_ID_MENU_ALARM);
        }

        setContentView(R.layout.intro);
    }
    
    @Override
    protected void onResume() {
        super.onResume();
        
        // 현재 로컬 DB 버전을 얻는다.
        mLocalDbVersion = Util.getPreferenceStringValue(this, Constants.PREF_DB_VERSION, null);
        Log.d(TAG, "mLocalDbVersion : " + mLocalDbVersion);
        // 서버 DB 버전을 얻는다.
        handler.sendEmptyMessage(Constants.MSG_CHECK_SERVER_DB_VERSION);
    }

    private Handler handler = new Handler() {
        public void handleMessage(android.os.Message msg) {
            switch(msg.what) {
                case Constants.MSG_CHECK_SERVER_DB_VERSION:
                    Log.d(TAG, "checking server db version.");
                    showDialog(Constants.DIALOG_CHECK_SERVER_DB_VERSION);
                    new Thread() {
                        public void run() {
                            HttpClient client = new DefaultHttpClient();
                            String versionUrl = getString(R.string.version_url);
                            HttpGet request = new HttpGet(versionUrl);
                            
                            HttpParams params = client.getParams();
                            HttpConnectionParams.setConnectionTimeout(params, 5000);
                            HttpConnectionParams.setSoTimeout(params, 5000);
                            
                            InputStream is = null;
                            try {
                                HttpResponse response = client.execute(request);
                                if(response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
                                    is = response.getEntity().getContent();
                                    DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
                                    Document doc = builder.parse(is);
                                    
                                    mServerDbVersion = getElementValue(doc, "version");
                                    Log.d(TAG, "mServerDbVersion : " + mServerDbVersion);

                                    mServerDbZipFilename = getElementValue(doc, "zipfile_name");
                                    Log.d(TAG, "mServerDbZipFilename : " + mServerDbZipFilename);
                                    
                                    mServerDbZipFileSize = Integer.parseInt(getElementValue(doc, "zipfile_size"));
                                    Log.d(TAG, "mServerDbZipFileSize : " + mServerDbZipFileSize);
                                    
                                    handler.sendEmptyMessage(Constants.MSG_CHECK_SERVER_DB_VERSION_END);
                                }
                            } catch (Exception e) {
                                Log.e(TAG, "check server db version", e);
                                handler.sendEmptyMessage(Constants.MSG_CHECK_SERVER_DB_VERSION_ERROR);
                            } finally {
                                if(is != null) try { is.close(); } catch(Exception e) {}
                            }
                        };
                    }.start();
                    break;
                case Constants.MSG_CHECK_SERVER_DB_VERSION_END:
                    Log.d(TAG, "checking server db version end.");
                    dismissDialog(Constants.DIALOG_CHECK_SERVER_DB_VERSION);
                    
                    if(!TextUtils.isEmpty(mLocalDbVersion) && mLocalDbVersion.equals(mServerDbVersion)) {
                        // 최신 버전임.
                        Log.d(TAG, "local db is the latest version.");
                        
                        Intent intent = new Intent(IntroActivity.this, MainActivity.class);
                        if(mRemoveNotification) {
                            intent.putExtra(Constants.EXTRA_SHOW_TODAY, true);
                        }
                        
                        startActivity(intent);
                        IntroActivity.this.finish();
                    } else {
                        // 최신 버전이 아니어서 DB를 다운로드 해야 함.
                        Log.d(TAG, "the latest version is available.");
                        sendEmptyMessage(Constants.MSG_DOWNLOAD_DB_FILE);
                    }
                    break;
                case Constants.MSG_CHECK_SERVER_DB_VERSION_ERROR:
                    Log.d(TAG, "error in checking server db version.");
                    dismissDialog(Constants.DIALOG_CHECK_SERVER_DB_VERSION);
                    // 지장이 없을 가능성이 크므로, 에러창을 표시하지 않고 그냥 진행(finish & start)한다.
                    startActivity(new Intent(IntroActivity.this, MainActivity.class));
                    IntroActivity.this.finish();
                    break;
                case Constants.MSG_DOWNLOAD_DB_FILE:
                    Log.d(TAG, "downloading db file.");
                    showDialog(Constants.DIALOG_DB_DOWNLOAD);
                    new Thread() {
                        public void run() {
                            HttpClient client = new DefaultHttpClient();
                            String versionUrl = getString(R.string.server_url) + mServerDbZipFilename;
                            HttpGet request = new HttpGet(versionUrl);
                            
                            HttpParams params = client.getParams();
                            HttpConnectionParams.setConnectionTimeout(params, 5000);
                            HttpConnectionParams.setSoTimeout(params, 5000);
                            
                            InputStream is = null;
                            FileOutputStream fo = null;
                            try {
                                HttpResponse response = client.execute(request);
                                if(response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
                                    is = response.getEntity().getContent();
                                    IntroActivity.this.deleteFile(Constants.TMP_DB_ZIP_FILE);
                                    fo = IntroActivity.this.openFileOutput(Constants.TMP_DB_ZIP_FILE, MODE_PRIVATE);
                                    BufferedOutputStream bo = new BufferedOutputStream(fo);
                                    BufferedInputStream bi = new BufferedInputStream(is);

                                    mCurrentDownloadSize = 0;

                                    byte[] buffer = new byte[4096];
                                    int len = 0;
                                    while ((len = bi.read(buffer)) != -1) {
                                        bo.write(buffer, 0, len);
                                        mCurrentDownloadSize += len;
                                        handler.sendEmptyMessage(Constants.MSG_UPDATE_PROGRESS_BAR);
                                    }
                                    
                                    handler.sendEmptyMessage(Constants.MSG_UPDATE_PROGRESS_BAR);
                                    bo.flush();
                                    
                                    handler.sendEmptyMessage(Constants.MSG_DOWNLOAD_DB_FILE_END);
                                }
                            } catch (Exception e) {
                                Log.e(TAG, "download server db file", e);
                                handler.sendEmptyMessage(Constants.MSG_CHECK_SERVER_DB_VERSION_ERROR);
                            } finally {
                                if(is != null) try { is.close(); } catch(Exception e) {}
                            }
                        };
                    }.start();
                    break;
                case Constants.MSG_UPDATE_PROGRESS_BAR:
                    mDownloadProgressDialog.setProgress(mCurrentDownloadSize);
                    break;
                case Constants.MSG_DOWNLOAD_DB_FILE_END:
                    Log.d(TAG, "db file download completed.");
                    dismissDialog(Constants.DIALOG_DB_DOWNLOAD);
                    // DB 파일 복사
                    try {
                        Util.copyDBFile(IntroActivity.this);
                        Log.d(TAG, "copy of the db file was completed.");
                        
                        // preference 값 갱신
                        Util.savePreference(IntroActivity.this, Constants.PREF_DB_VERSION, mServerDbVersion);
                        IntroActivity.this.startActivity(new Intent(IntroActivity.this, MainActivity.class));
                        IntroActivity.this.finish();
                    } catch(Exception e) {
                        Log.e(TAG, "copy db file", e);
                        handler.sendEmptyMessage(Constants.MSG_COPY_DB_FILE_ERROR);
                    }
                    break;
                case Constants.MSG_DOWNLOAD_DB_FILE_ERROR:
                    Log.d(TAG, "error in downloading db file.");
                    dismissDialog(Constants.DIALOG_DB_DOWNLOAD);
                    showDialog(Constants.DIALOG_DB_DOWNLOAD_ERROR);
                    break;
                case Constants.MSG_COPY_DB_FILE_ERROR:
                    Log.d(TAG, "error in copying db file.");
                    showDialog(Constants.DIALOG_DB_COPY_ERROR);
                    break;
            }
        };
    };
    
    protected Dialog onCreateDialog(int id) {
        switch(id) {
            case Constants.DIALOG_CHECK_SERVER_DB_VERSION:
                ProgressDialog checkProgressDialog = new ProgressDialog(this);
                checkProgressDialog.setMessage(getString(R.string.check_server_db_version));
                checkProgressDialog.setIndeterminate(true);
                checkProgressDialog.setCancelable(true);
                checkProgressDialog.setOnCancelListener(new OnCancelListener() {
                    @Override
                    public void onCancel(DialogInterface dialog) {
                        finish();
                    }
                });
                return checkProgressDialog;
            case Constants.DIALOG_DB_DOWNLOAD:
                mDownloadProgressDialog = new ProgressDialog(this);
                mDownloadProgressDialog.setIcon(android.R.drawable.ic_dialog_alert);
                mDownloadProgressDialog.setTitle(R.string.download_db_file);
                mDownloadProgressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
                mDownloadProgressDialog.setCancelable(false);
                mDownloadProgressDialog.setMax(mServerDbZipFileSize); // 실제 file size
                mDownloadProgressDialog.setButton(getText(R.string.cancel_btn), new DialogInterface.OnClickListener() {
                    public void onClick(DialogInterface dialog, int whichButton) {
                        finish();
                    }
                });
                return mDownloadProgressDialog;
            case Constants.DIALOG_DB_DOWNLOAD_ERROR:
                return new AlertDialog.Builder(this)
                .setIcon(android.R.drawable.ic_dialog_alert)
                .setTitle(R.string.error)
                .setMessage(R.string.download_db_file_error)
                .setCancelable(false)
                .setPositiveButton(R.string.ok_btn, new DialogInterface.OnClickListener() {
                    public void onClick(DialogInterface dialog, int whichButton) {
                        finish();
                    }
                })
                .create();
            case Constants.DIALOG_DB_COPY_ERROR:
                return new AlertDialog.Builder(this)
                .setIcon(android.R.drawable.ic_dialog_alert)
                .setTitle(R.string.error)
                .setMessage(R.string.download_db_file_error)
                .setCancelable(false)
                .setPositiveButton(R.string.ok_btn, new DialogInterface.OnClickListener() {
                    public void onClick(DialogInterface dialog, int whichButton) {
                        finish();
                    }
                })
                .create();
        }
     
        return null;
    }
    
    /**
     * XML에서 특정 element의 값을 구한다.
     * @param doc
     * @param elementName
     * @return
     */
    private String getElementValue(Document doc, String elementName) {
        NodeList version = doc.getElementsByTagName(elementName);
        Element versionElement = (Element) version.item(0);
        String value = versionElement.getFirstChild().getNodeValue();
        
        return value;
    }
}
